package com.threegroup.admin.security.config;

import com.threegroup.admin.enums.SuperAdminEnum;
import com.threegroup.admin.security.user.SecurityUser;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

@Service("adminAuthorizeService")
public class AdminAuthorizeService {

    private static String START_WITH = "/api/";

    /**
     * 需要登录但是不需要验权的url
     */
    private static List<String> urls = new ArrayList<String>() {{
        add("/api/sys/dict/type/**");
        add("/api/sys/menu/**");
    }};

    /**
     * 超级管理员管理员白名单url
     */
    private static List<String> superAdminUrl = new ArrayList<String>() {{
        add("/categoryMenu/getAll");
        add("/categoryMenu/getButtonAll");
        add("/categoryMenu/getCategoryMenuByUserName");
    }};

    /**
     * springframework自带的任意路由正则
     */
    private static AntPathMatcher antPathMatcher = new AntPathMatcher();

    public boolean check(Authentication authentication, HttpServletRequest request) {
        Object principal = authentication.getPrincipal();
        // 判断是否是认证的用户
        if (principal != null && principal instanceof UserDetails) {
            SecurityUser user = (SecurityUser) principal;
            // 获取认证用户里的url列表
            List<SimpleGrantedAuthority> authorities = (List<SimpleGrantedAuthority>) user.getAuthorities();
            String permission = getPermission(request);

            // 判断permission列表里是否包含request请求的permission
            boolean contains = authorities.stream()
                    .map(SimpleGrantedAuthority::getAuthority)
                    .anyMatch(a -> antPathMatcher.match(a, permission));

            // 判断访问的url是否在白名单中
            boolean whiteContains = checkWhiteList(request.getRequestURI());
            // 检查特定url
            boolean superContains = checkSuperUrl(request.getRequestURI(), user);
            // 超级账号放权全部功能
            boolean checkSuperAdmin = checkSuperAdmin(user);
            // 满足一个即可放行
            return contains || whiteContains || superContains || checkSuperAdmin;
        }
        return false;
    }

    /**
     * 权限转换
     * @param request
     * @return
     */
    private String getPermission(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        String permission = "";
        if (requestURI.startsWith(START_WITH)) {
            String uri = requestURI.substring(START_WITH.length());
            permission = String.join(":", uri.split("/"));
        }
        return permission;
    }

    /**
     * 校验用户是否登录
     *
     * @return
     */
    public boolean checkUserLogin() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (!(auth instanceof AnonymousAuthenticationToken)) {
            return true;
        }
        return false;
    }

    /**
     * 白名单检测
     *
     * @param url
     * @return
     */
    public boolean checkWhiteList(String url) {
        return urls.stream().anyMatch(a -> antPathMatcher.match(a, url));
    }

    ;

    /**
     * 超管白名单检测
     *
     * @param url
     * @return
     */
    public boolean checkSuperUrl(String url, SecurityUser securityUser) {
        if (!UserType.SuperAdmin.getName().equals(securityUser.getSysRole())) {
            return superAdminUrl.stream().anyMatch(a -> antPathMatcher.match(a, url));
        } else {
            return true;
        }
    }

    /**
     * 超管账号Check
     *
     * @param securityUser
     * @return
     */
    public boolean checkSuperAdmin(SecurityUser securityUser) {
        if (SuperAdminEnum.YES.value() == securityUser.getSuperAdmin()) {
            return true;
        } else {
            return false;
        }
    }

    public enum UserType {
        SuperAdmin("超级管理员"),
        NormalUser("普通员工");
        private String name;

        UserType(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }
}
